<template>
	<view class="ifun-tree-select" v-show="visible">
		<view class="body" :class="[beforeClose?'hidden':'']">
			<view class="header" :class="[round?'round':'']">
				<text class="cancel-btn btn" @click="handleCancel">取消</text>
				<text class="title" v-if="title">{{title}}</text>
				<text class="confirm-btn btn" @click="handleConfirm">确定</text>
			</view>
			<view class="main">
				<view class="current-node">
					<view class="node-label">
						<image @click="handleBackNode" src="../../static/left.svg" mode="aspectFit"
							style="width: 20px;height: 15px;"></image>
						<text class="current-node-label">{{currentNode[options.label]||'请选择'}}</text>
					</view>
					<text v-if="clearable" class="clear-btn btn" @click="handleClear">清除</text>
				</view>
				<view class="node-container">
					<template v-if="!showTree">
						<view class="node-item" :class="item[options.value]==currentNode[options.value]?'selected':''"
							v-for="(item,index) in viewData" :key="item[options.key]" @click="()=>handleSelect(item,index)">
							<text class="node-item-label">{{item[options.label]}}</text>
							<!-- 多选 -->
							<view v-if="showCheckbox(item)" class="multiple-box" @click.stop="handleMultipleSelect(item)">
								<checkbox :checked="multipleSelectIds.includes(item[options.key])"></checkbox>
							</view>
						</view>
					</template>
					<template v-else>
						<SelectNode :multiple="multiple" :selected="multiple?multipleSelectIds:currentNode" :checkStrictly="checkStrictly" :data="data" @click="handleTreeSelect" :options="options"  />
					</template>
				</view>
			</view>
			
		</view>

		<view class="picker-mask" :class="[beforeClose?'hidden':'']" @click="cancel"></view>
	</view>
</template>

<script>
	import SelectNode from './select-node.vue';
	import TreeSelect from './tree-select.js'
	
	// 节点信息映射
	const DefaultOptions = {
		label: 'label',
		value: 'value',
		key: 'value',
		children: 'children'
	}
	export default {
		name: "ifun-tree-select",
		mixins:[TreeSelect],
		components:{
			SelectNode
		},
		props: {
			
			data: {
				type: Array,
				default: () => ([])
			},
			title: String,
			visible: Boolean,
			treeOptions: {
				type: Object,
				defautl: () => ({})
			},
			round: Boolean,
			clearable: Boolean,
			checkStrictly: {
				type: Boolean,
				default: true
			},
			multiple:Boolean,
			showTree:Boolean,
			lazy:Boolean,
			load:Function,
			checked:Array
		},
		data() {
			return {
				selectValue: [],
				// 按照数据key值映射子数据
				nodeMapData: {},
				// 当前的节点数据
				viewData: [],
				// 当前层级
				currentLevel: 1,
				currentNode: {},
				// 关闭之前
				beforeClose:false,
				// 多选的节点数据
				multipleSelectData:[],
				// 多选临时变量存储
				tempMultipleSelectData:[]
			};
		},
		watch: {
			visible:{
				immediate:true,
				handler(bool){
					if(bool && this.multiple){
						const {
							value
						} = this.options
						if(this.checked){
							this.multipleSelectData = this.multipleSelectData.filter(item=>this.checked.includes(item[value]))
						}
						
						this.tempMultipleSelectData = [...this.multipleSelectData];
					}
				}
			},
			data: {
				immediate: true,
				deep: true,
				handler(arr) {
					if(!this.showTree){
						this.viewData = arr;
						this.initMapData(arr);
					}
				}
			}
		},
		computed: {
			multipleSelectIds(){
				
				return this.tempMultipleSelectData.map(item=>item[this.options.value])
			},
			options() {
				return {
					...DefaultOptions,
					...this.treeOptions
				}
			},
			
		},
		methods: {
			showCheckbox(node){
				if(!this.multiple){
					return false;
				}
				if(this.checkStrictly){
					return true;
				}
				
				// 严格关联选择，需要选择到叶子结点
				let arr = this.nodeMapData[node[this.options.key]]
				return !arr || arr.length<1
			},
			handleMultipleSelect(info){
				const {
					value
				} = this.options
				// let index = this.multipleSelectData.findIndex(item=>item[value] == info[value])
				let index = this.tempMultipleSelectData.findIndex(item=>item[value] == info[value])
				if(index>-1){
					// this.multipleSelectData.splice(index,1)
					this.tempMultipleSelectData.splice(index,1)
				}else{
					// this.multipleSelectData.push(info)
					this.tempMultipleSelectData.push(info)
				}
				
			},
			handleClear() {
				this.selectValue = [];
				this.currentNode = {};
				this.currentLevel = 1;
				this.multipleSelectData = [];
				this.tempMultipleSelectData = [];
				this.handleBackNode()
			},
			handleBackNode() {
				if (this.currentLevel == 1 || this.currentLevel - 1 == 1) {
					// 第一级为所有数据
					this.currentLevel = 1
					this.viewData = this.data;
					return
				}
				this.currentLevel--;

				let info = this.selectValue[this.currentLevel - 2]
				let arr = this.nodeMapData[info[this.options.key]]
				this.viewData = arr;

			},
			async handleSelect(nodeInfo, nodeIndex) {

				if (this.selectValue[this.currentLevel - 1]) {
					this.selectValue[this.currentLevel - 1] = nodeInfo
				} else {
					this.selectValue.push(nodeInfo)
				}
				// 当前选择的节点信息
				this.currentNode = nodeInfo
				
				// 增加懒加载模式，远程加载
				// 下级节点数据，不存在；存在远程加载回调，则执行回调请求
				let arr = this.nodeMapData[nodeInfo[this.options.key]]
				if(this.lazy && (!arr || arr.length<1)){
					arr = await this.load(nodeInfo);
					this.nodeMapData[nodeInfo[this.options.key]] = arr;
				}
				if (arr && arr.length > 0) {
					this.currentLevel++;
					this.viewData = arr;
				}

			},
			initMapData(data) {

				const {
					key,
					children
				} = this.options
				if (!Array.isArray(data)) {
					return []
				}
				let len = data.length;
				let arr = []
				for (let i = 0; i < len; i++) {
					let info = data[i]
					arr.push(info)
					let temp = []
					if (info[children]) {
						temp = this.initMapData(info[children])
						this.nodeMapData[info[key]] = temp;
					}
				}

				return arr;
			},
			handleConfirm() {
				// 确认选择
				if(this.showTree){
					this.handleTreeConfirm();
					return
				}
				if (!this.checkStrictly) {
					this.handleConfirmNotCheckStrictly();
					return
				}
				
				this.handleConfirmEmitValue()
			},
			handleConfirmNotCheckStrictly(){
				const {
					key
				} = this.options;
				// 多选，空也可以提交
				if(this.multiple){
					this.handleConfirmEmitValue()
					return
				}
				// 需要严格关联选择时，则需要选择到节点最后一级
				// 节点有被选择
				let bool = this.viewData.find(item => item[key] == this.currentNode[key])
				if (!bool) {
					// 说明当前选择的节点不是当前视图层级中的数据
					uni.showToast({
						icon: "error",
						mask: true,
						title: '请选择叶子节点!',
					})
					return
				}
				this.handleConfirmEmitValue()
				
			},
			handleConfirmEmitValue(){
				const {
					key
				} = this.options;
				this.multipleSelectData = this.tempMultipleSelectData;
				this.tempMultipleSelectData = [];
				if(this.multiple){
					this.$emit('ok',this.multipleSelectData,);
				}else{
					let index = this.selectValue.findIndex(item => item[key] == this.currentNode[key])
					this.$emit('ok', this.currentNode, this.selectValue.slice(0, index + 1))
				}
				this.tempMultipleSelectData = [];
				this.cancel()
			},
			handleCancel() {
				this.tempMultipleSelectData = [];
				this.cancel();
			},
			cancel() {
				this.beforeClose = true;
				// 等待动画执行结束
				setTimeout(()=>{
					this.$emit('update:visible', false);
					this.beforeClose = false;
					this.$emit('close');
				},400);
			}
		}
	}
</script>

<style lang="less" scoped>
	@keyframes fadeIn {
		0%{
			opacity: 0;
		}
		100%{
			opacity: 1;
		}
	}
	@keyframes fadeOut {
		0%{
			opacity: 1;
		}
		100%{
			opacity: 0;
		}
	}
	@keyframes slideInUp {
		0%{
			transform: translate3d(0, 100%, 0);
			visibility: visible;
		}
		100%{
			transform: translate3d(0, 0, 0);
		}
	}
	@keyframes slideOutUp {
		0%{
			transform: translate3d(0, 0, 0);
			visibility: visible;
		}
		100%{
			transform: translate3d(0, 100%, 0);
		}
	}
	.ifun-tree-select {
		position: fixed;
		top: 0;
		height: 100%;
		left: 0;
		width: 100%;
		z-index: 999;
		transition: 300ms;

		.picker-mask {
			position: absolute;
			top: 0;
			left: 0;
			width: 100%;
			height: 100%;
			background: rgba(0, 0, 0, 0.5);
			z-index: 10;
			animation: fadeIn linear 300ms both;
			&.hidden{
				animation: fadeOut linear 300ms both;
			}
		}

		.body {
			position: absolute;
			top: 20%;
			left: 0;
			width: 100%;
			bottom: 0;
			z-index: 100;
			animation: slideInUp linear 300ms both;
			&.hidden{
				animation: slideOutUp linear 300ms both;
			}
			.btn {
				margin: 0;
				padding: 0;
				border: none;
				font-size: 14px;
				color: #333;
				flex: 0 0 50px;
				text-align: center;

				&.confirm-btn {
					color: #1677ff;
				}

				&.clear-btn {
					color: #f5222d;
				}
			}
		}

		.header {
			background: #fff;
			border-bottom: 1px solid #eee;
			display: flex;
			align-items: center;
			padding: 5px 10px;
			height: 50px;

			&.round {
				border-radius: 10px 10px 0 0;
			}



			.title {
				flex: 1;
				text-align: center;
				color: #000;
				font-size: 16px;
			}
		}

		.main {
			background: #fff;
			height: calc(100% - 50px);
			overflow: auto;
			padding: 15px;
			color: #000;

			.current-node {
				height: 35px;
				display: flex;
				align-items: center;
				font-size: 16px;
				margin-bottom: 5px;
				justify-content: space-between;

				.node-label {
					width: calc(100% - 50px);
					display: flex;
					align-items: center;

					.current-node-label {

						white-space: nowrap;
						text-overflow: ellipsis;
						overflow: hidden;
					}
				}

			}

			.node-container {
				.node-item {
					height: 30px;
					line-height: 30px;
					width: 100%;
					padding-left: 5px;
					display: flex;
					gap:5px;

					&.selected {
						background: #eee;
					}

					.node-item-label {
						text-overflow: ellipsis;
						overflow: hidden;
						white-space: nowrap;
						flex: 1;
						display: inline-block;
					}
				}
			}
		}
	}
</style>